﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;


namespace ModifyMimeTypes
{
    //Class used to retrieve mime data from Active Directory
    class MimeHelper
    {
        DirectoryEntry org; //Directory entry for the Exchange organization container

        public MimeHelper()
        {
            this.org = GetExchangeOrg();
        }
        ~MimeHelper()
        {
            org.Dispose();
        }

        //Returns a directory entry for the Exchange Organization object i.e.
        //CN=ORGNAME,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=domain,DC=suffix
        private DirectoryEntry GetExchangeOrg()
        {
            //First find the configuration container
            DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
            DirectoryEntry configContainer = new DirectoryEntry("LDAP://" +
                rootDSE.Properties["configurationNamingContext"].Value);

            //Create a directory search to search the config container
            DirectorySearcher configSearcher = new DirectorySearcher(configContainer);

            //Search for the org container
            configSearcher.Filter = "(objectclass=msExchOrganizationContainer)";
            SearchResult result = configSearcher.FindOne();

            //Get the Org
            DirectoryEntry org = result.GetDirectoryEntry();

            //Do cleanup
            rootDSE.Dispose();
            configContainer.Dispose();
            configSearcher.Dispose();

            return org;
        }

        //Retrieves the msExchMimeTypes value from the Org container
        private byte[] GetMsExchMimeTypes()
        {
            byte[] mimeTypes = new byte[0];

            mimeTypes = (byte[])org.Properties["msExchMimeTypes"].Value;

            return mimeTypes;
        }

        //Saves a stream of bytes back to the msExchMimeTypes property
        private bool SaveMimeTypes(byte[] mimeTypes)
        {
            bool success = false;

            org.Properties["msExchMimeTypes"].Value = mimeTypes;
            org.CommitChanges();

            return success;
        }

        //Takes the byte value of msExchMimeTypes retrieved from AD and
        //returns a list of string values
        private BindingList<string> GetListFromMimeTypes(byte[] mimeTypes)
        {
            BindingList<string> mimeTypeList = new BindingList<string>(); //The return value

            string mimeType = ""; //The current mimeType being built

            //Loop through each byte in the array and convert to ascii
            for (int i = 0; i < mimeTypes.Length; i++)
            {
                byte current = mimeTypes[i]; //The current byte

                //This is the null terminator at the end of a string
                //Finish off this mime type and get ready to start a new one
                if (current == 0) 
                {
                    //This isn't the very end of the file (contains two nulls),
                    //so add the string to the list
                    if (mimeType.Length != 0)
                    {
                        mimeTypeList.Add(mimeType.ToLower());
                        mimeType = "";
                    }

                    continue;
                }

                //Convert
                mimeType += System.Convert.ToChar(current);
            }

            return mimeTypeList;
        }

        //Takes a list of strings of mime types and converts it back to a byte
        //array. The byte array can be written back to AD
        private byte[] GetBytesFromMimeTypeList(BindingList<string> mimeTypeList)
        {
            byte[] mimeTypes = new byte[GetMimeByteArraySize(mimeTypeList)];
            int pos = 0; //Keep track of the current location in the byte array

            //Loop through each string in the list
            for (int i = 0; i < mimeTypeList.Count; i++)
            {
                string type = mimeTypeList[i]; //Current mime type

                //Loop through each char in the string and convert to hex
                for (int j = 0; j < type.Length; j++)
                {
                    mimeTypes[pos++] = (byte)System.Convert.ToInt32(type[j]);
                }

                mimeTypes[pos++] = 0;
            }

            return mimeTypes;
        }

        //Takes a list of strings of mime types and determines how large
        //the byte array needs to be to hold them
        private int GetMimeByteArraySize(BindingList<string> mimeTypeList)
        {
            int count = 0;

            foreach (string type in mimeTypeList)
            {
                count += type.Length;
            }

            //Add extra space for the null terminators
            count += (mimeTypeList.Count + 1);

            return count;
        }

        //Public method which returns a List<string> containing all mime types
        //for the org.
        public BindingList<string> GetMimeTypes()
        {
            return GetListFromMimeTypes(GetMsExchMimeTypes());
        }

        //Public method used to save a modified List<string> of mime types
        //back to AD.
        public bool SaveMimeTypes(BindingList<string> mimeTypeList)
        {
            bool success = false;

            SaveMimeTypes(GetBytesFromMimeTypeList(mimeTypeList));

            return success;
        }
    }
}
